package com.cloudeasy.post.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudeasy.api.enums.ResultCodeEnum;
import com.cloudeasy.api.exception.CloudEasyException;
import com.cloudeasy.api.util.SnowFlake;
import com.cloudeasy.api.vo.Result;
import com.cloudeasy.api.vo.label.LabelVO;
import com.cloudeasy.post.client.LabelClient;
import com.cloudeasy.post.dao.mapper.PostMapper;
import com.cloudeasy.post.dto.PostDTO;
import com.cloudeasy.post.po.Post;
import com.cloudeasy.post.po.PostLabel;
import com.cloudeasy.post.service.expand.AmqpService;
import com.cloudeasy.post.util.IPageUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
public class PostService extends ServiceImpl<PostMapper, Post> {
    private static final Integer RECOMMEND_COUNT = 20;

    private final SnowFlake snowFlake;

    private final ReplyService replyService;

    private final PostLabelService postLabelService;

    private final PostCollectService postCollectService;

    private final AmqpService amqpService;

    private final LabelClient labelClient;

    @Autowired
    public PostService(SnowFlake snowFlake, @Lazy ReplyService replyService, @Lazy PostLabelService postLabelService, @Lazy PostCollectService postCollectService, AmqpService amqpService, LabelClient labelClient) {
        this.snowFlake = snowFlake;
        this.replyService = replyService;
        this.postLabelService = postLabelService;
        this.postCollectService = postCollectService;
        this.amqpService = amqpService;
        this.labelClient = labelClient;
    }

    /**
     * 发帖
     *
     * @param authorId 作者Id
     * @param postDTO  {@link PostDTO}
     * @return {@link Boolean}
     */
    public Boolean save(String authorId, PostDTO postDTO) {
        String id = String.valueOf(snowFlake.nextId());
        Post post = Post.builder().id(id).authorId(authorId).build();
        BeanUtils.copyProperties(postDTO, post);

        amqpService.sendAmqp(postDTO.getArea(), null, 1);

        return this.save(post) && postLabelService.update(id, postDTO.getLabelIds());
    }

    /**
     * 删帖
     *
     * @param post {@link Post}
     * @return {@link Boolean}
     */
    public boolean removeById(Post post) {
        List<String> labelIds = postLabelService.getByPostId(post.getId()).stream().map(PostLabel::getLabelId).collect(Collectors.toList());

        amqpService.sendAmqp(post.getArea(), labelIds, -1);

        replyService.removeByPostId(post.getId());
        postLabelService.removeByPostIdAndLabelIds(post.getId(), labelIds);
        postCollectService.removeByPostId(post.getId());
        return this.removeById(post.getId());
    }

    /**
     * 根据作者Id获取帖子
     *
     * @param authorId 作者Id
     * @return {@link List<Post>}
     */
    public List<Post> getByAuthorId(String authorId) {
        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("author_id", authorId);
        return this.list(queryWrapper);
    }

    /**
     * 根据作者Id获取帖子
     *
     * @param authorId 作者Id
     * @param page     页数
     * @param size     每页大小
     * @return {@link IPage<Post>}
     */
    public IPage<Post> getByAuthorIdPage(String authorId, Integer page, Integer size) {
        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("author_id", authorId);
        IPage<Post> postTempIPage = IPageUtil.compose(page, size);
        return this.page(postTempIPage, queryWrapper);
    }

    /**
     * 评论处理逻辑
     *
     * @param postId 帖子Id
     * @return 帖子作者Id
     */
    public String review(String postId) {
        Post post = this.getById(postId);
        if (post == null) {
            throw new CloudEasyException(ResultCodeEnum.ID_NOT_EXISTS);
        }

        post.setReplyCount(post.getReplyCount() + 1);
        post.setLastReplyTime(new Date());
        this.updateById(post);
        return post.getAuthorId();
    }

    /**
     * 删除评论
     *
     * @param postId 帖子Id
     * @return {@link Boolean}
     */
    public Boolean removeReview(String postId) {
        Post post = this.getById(postId);
        if (post == null) {
            throw new CloudEasyException(ResultCodeEnum.ID_NOT_EXISTS);
        }

        post.setReplyCount(post.getReplyCount() - 1);

        return this.updateById(post);
    }

    /**
     * 收藏
     *
     * @param postId 帖子Id
     * @return {@link Boolean}
     */
    public Boolean collect(String postId) {
        Post post = this.getById(postId);
        if (post == null) {
            throw new CloudEasyException(ResultCodeEnum.ID_NOT_EXISTS);
        }
        post.setCollectCount(post.getCollectCount() + 1);
        return this.updateById(post);
    }

    /**
     * 取消收藏
     *
     * @param postId 帖子Id
     * @return {@link Boolean}
     */
    public Boolean removeCollect(String postId) {
        Post post = this.getById(postId);
        if (post == null) {
            throw new CloudEasyException(ResultCodeEnum.ID_NOT_EXISTS);
        }
        post.setCollectCount(post.getCollectCount() - 1);
        return this.updateById(post);
    }

    /**
     * 推荐
     *
     * @param userId 当前用户Id
     * @return {@link List<Post>}
     */
    public List<Post> recommend(String userId) {
        Result<List<LabelVO>> result = labelClient.getAttention(userId);
        if (!result.getCode().equals(ResultCodeEnum.SUCCESS.getCode())) {
            throw new CloudEasyException(Objects.requireNonNull(ResultCodeEnum.get(result.getCode())));
        }
        List<String> labelIds = result.getData().stream().map(LabelVO::getId).collect(Collectors.toList());
        int count = (int) (RECOMMEND_COUNT * 0.7);
        List<Post> endPosts = new ArrayList<>();
        // 如果没有关注标签，随机推送
        if (labelIds.size() > 0) {
            List<String> postIds = postLabelService.getByLabelIds(labelIds).stream().map(PostLabel::getPostId).collect(Collectors.toList());
            Collections.shuffle(postIds);
            List<String> subPostIds = postIds.subList(0, Math.min(postIds.size(), count));
            int size = RECOMMEND_COUNT - subPostIds.size();
            if (subPostIds.size() > 0) {
                endPosts.addAll(this.listByIds(subPostIds));
                List<Post> posts = this.executeList(subPostIds);
                Collections.shuffle(posts);
                endPosts.addAll(posts.subList(0, Math.min(posts.size(), size)));
            } else {
                List<Post> posts = this.list();
                endPosts.addAll(posts.subList(0, Math.min(posts.size(), count)));
            }
        } else {
            List<Post> posts = this.list();
            endPosts.addAll(posts.subList(0, Math.min(posts.size(), count)));
        }
        return endPosts;
    }

    /**
     * 获取不在帖子Id列表之内的记录
     *
     * @param postIds 帖子Id列表
     * @return {@link List<Post>}
     */
    public List<Post> executeList(List<String> postIds) {
        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
        queryWrapper.notIn("id", postIds);
        return this.list(queryWrapper);
    }
}
